/**
 * это главный файл
 * программа вычисляет некоторые сложные моменты в выполнении д.з.
 * попрошу тут не редактировать (ибо другим ваше редактирование может не надо), а копировать себе на комп
 * rumterg@gmail.com
 */
import java.io.*;
import java.util.*;

class lab {
	/**
	 * прочитать из файла описание цепей и построить матрицу R, записав в другой файл
	 * @param String source входной файл с описанием цепей
	 * @param String distination выходной файл с матрицей R
	 */
	private static void branchesToR (String source, String distination) {
		try {
			Graph g = GraphsUtils.readGraphByBranches (source);
			BufferedWriter br = new BufferedWriter (new FileWriter (distination));
			br.write (g.count () + "");
			br.newLine ();
			for (int i = 0; i < g.count (); ++ i) {
				for (int j = 0; j < g.count (); ++ j)
					br.write (g.getEdge (i, j) + " ");
				br.newLine ();
			}
			br.close ();
		}
		catch (Exception e) {
			System.out.println ("Error in branchesToR: " + e);
		}
	}
	/**
	 * прочитать из файла матрицу R, найти степени всех вершин и записать их в выходной файл
	 * @param String source входной файл с матрицей R
	 * @param String distination выходной файл со степенями вершин и с количеством вершин с нечётными степенями
	 */
	private static void degreeFromR (String source, String distination) {
		try {
			Graph g = GraphsUtils.readGraphByR (source);
			BufferedWriter br = new BufferedWriter (new FileWriter (distination));
			int c = 0;
			for (int i = 0; i < g.count (); ++ i) {
				br.write (g.degree (i) + " ");
				if (g.degree (i) % 2 == 1)
					++ c;
			}
			br.newLine ();
			br.write (c + "");
			br.close ();
		}
		catch (Exception e) {
			System.out.println ("Error in degreeFromR: " + e);
		}
	}
	/**
	 * прочитать из файла матрицу R и построить эйлеров цикл, если его построить нельзя выскочит Exception
	 * в таком случае нужно подредактировать матрицу R, чтобы было либо 0 либо 2 вершины с нечётными степенями
	 * @param String source входной файл с матрицей R
	 * @param String distination выходной файл с эйлеровым циклом
	 */
	private static void eulerCycle (String source, String distination){
		try {
			Graph g = GraphsUtils.readGraphByR (source);
			ArrayList vertices = GraphsUtils.eulerCycle (g);
			BufferedWriter br = new BufferedWriter (new FileWriter (distination));
			int u = - 1;
			for (int i = 0; i < vertices.size (); ++ i) {
				int v = ((Integer)vertices.get (i)).intValue () + 1;
				if (u != - 1) {
					br.write (u + " " + v);
					br.newLine ();
				}
				u = v;
			}
			br.close ();
		}
		catch (Exception e) {
			System.out.println ("Error in eulerCycle: " + e);
		}
	}
	/**
	 * прочитать из файла матрицу R и вывести в другой файл список всех рёбер графа
	 * @param String source входной файл с матрицей R
	 * @param String distination выходной файл со списком рёбер
	 */
	private static void edges (String source, String distination){
		try {
			Graph g = GraphsUtils.readGraphByR (source);
			BufferedWriter br = new BufferedWriter (new FileWriter (distination));
			for (int i = 0; i < g.count (); ++ i) 
				for (int j = i + 1; j < g.count (); ++ j)
					if (g.getEdge (i, j) > 0) {
						br.write ((i + 1) + " " + (j + 1) + " " + g.getEdge (i, j) + " ");
						br.newLine ();
					}
			br.close ();
		}
		catch (Exception e) {
			System.out.println ("Error in eulerCycle: " + e);
		}
	}
	/**
	 * прочитать из файла матрицу R, поменять некоторые вершины местами и новую матрицу R вывести в другой файл
	 * @param String source входной файл с матрицей R
	 * @param String distination выходной файл с новой матрицей R
	 */
	private static void swapsVertices (String source, String distination){
		try {
			Graph g = GraphsUtils.readGraphByR (source);

			// тут пишем, какие пары вершин меняем местами
			/*g.swap (0, 11);
			g.swap (2, 10);
			g.swap (1, 7);
			g.swap (4, 8);
			g.swap (5, 2);
			g.swap (6, 1);
			g.swap (2, 0);
			g.swap (9, 5);*/
			g.swap (0, 1);
			g.swap (2, 3);
			g.swap (3, 0);
			g.swap (4, 1);
			g.swap (1, 1);

			BufferedWriter br = new BufferedWriter (new FileWriter (distination));
			br.write (g.count () + "");
			br.newLine ();
			for (int i = 0; i < g.count (); ++ i) {
				for (int j = 0; j < g.count (); ++ j)
					br.write (g.getEdge (i, j) + " ");
				br.newLine ();
			}
			br.close ();
		}
		catch (Exception e) {
			System.out.println ("Error in swapsVertices: " + e);
		}
	}
	/**
	 * прочитать из файла матрицу R, в построенном по неё графе найти максимальную клику и вывести её в другой файл
	 * @param String source входной файл с матрицей R
	 * @param String distination выходной файл с максимальной кликой
	 */
	private static void findMaxFullGraph (String source, String distination) {
		try {
			Graph g = GraphsUtils.readGraphByR (source);
			ArrayList vertices = GraphsUtils.findMaxFullGraph (g);

			BufferedWriter br = new BufferedWriter (new FileWriter (distination));
			for (int i = 0; i < vertices.size (); ++ i) {
				int v = ((Integer)vertices.get (i)).intValue ();
				br.write ((v + 1) + " ");
			}
			br.close ();
		}
		catch (Exception e) {
			System.out.println ("Error in findMaxFullGraph: " + e);
		}
	}
	/**
	 * прочитать из файла матрицу R, в построенном по ней графе найти число Хадвигера и всё это дело вывести в выходной файл
	 * @param String source входной файл с матрицей R
	 * @param String distination выходной файл с описанием какие рёбра нужно стягивать, какой граф после каждого стягивания получается и с итоговым полным графом
	 */
	private static void findHadvigersNumbersEdges (String source, String distination){
		try {
			Graph g = GraphsUtils.readGraphByR (source);
			HadvigersResult hr = GraphsUtils.findHadvigersNumbersEdges (g);

			BufferedWriter br = new BufferedWriter (new FileWriter (distination));
			br.newLine ();
			br.write (hr.size () + "");
			br.newLine ();
			for (int i = 0; i < hr.size (); ++ i) {
				br.write ((hr.getV1 (i) + 1) + " " + (hr.getV2 (i) + 1));
				br.newLine ();
				Graph g2 = (Graph)hr.g_hist.get (i);
				for (int u = 0; u < g2.count (); ++ u) {
					for (int v = 0; v < g2.count (); ++ v)
						br.write (g2.getEdge (u, v) + " ");
					br.newLine ();
				}
				br.newLine ();
			}
			br.newLine ();
			br.write (hr.g.count () + "");
			br.newLine ();
			for (int i = 0; i < hr.g.count (); ++ i) {
				for (int j = 0; j < hr.g.count (); ++ j)
					br.write (hr.g.getEdge (i, j) + " ");
				br.newLine ();
			}
			br.close ();
		}
		catch (Exception e) {
			System.out.println ("Error in findHadvigersNumbersEdges: " + e);
		}
	}
	/**
	 * главный метод
	 * запуск Шаттла в космос
	 * @param String args[0] содержит число - номер действия
	 */
	public static void main (String args[]){
		try {
			if (args.length > 0)
				switch (Integer.parseInt (args[0])) {
					case 0:
						// описание цепей -> матрица R
						branchesToR ("branches.txt", "matrixR.txt");
						break;
					case 1:
						// матрица R -> степени вершин
						degreeFromR ("matrixR.txt", "degree.txt");
						break;
					case 2:
						// матрица R -> Эйлеров цикл
						eulerCycle ("matrixR.txt", "eulerCycle.txt");
						break;
					case 3:
						// матрица R ->  все рёбра графа
						edges ("matrixR.txt", "edges.txt");
						break;
					case 4:
						// матрица R -> новая матрица R
						swapsVertices ("matrixR.txt", "matrixRSwap.txt");
						break;
					case 5:
						// матрица R -> максимальная клика
						findMaxFullGraph ("matrixR.txt", "maxFullGraph.txt");
						break;
					case 6:
						// матрица R -> результаты поиска числа Хадвигера
						findHadvigersNumbersEdges ("matrixR.txt", "hadvigers.txt");
						break;
					default:
						// описание цепей -> матрица R
						branchesToR ("branches.txt", "matrixR.txt");
						break;
				}
			else {
				// описание цепей -> матрица R
				branchesToR ("branches.txt", "matrixR.txt");
			}
		}
		catch (Exception e) {
			System.out.println ("Error in main: " + e);
		}
	}
}